package aggregate

import (
	"context"
	"time"

	"gitee.com/leonscript/sally/v2/domain/entity"
	"github.com/bytedance/sonic"
	"gorm.io/gorm"
)

const (
	ReviewRejected = -1
	ReviewPassed   = 1
)

// ClerkService 工作流对外服务
// 对外提供了所有工作流服务
type ClerkService interface {
	WorkflowTemplateService

	WorkflowService
	TaskService
}

type WorkflowTemplateService interface {
	// 创建工作流模板
	AddWorkflowTemplate(ctx context.Context, workflowTemplateConfig WorkflowTemplateConfig) (workflowTemplateID string, nodeTemplateIDs []string, err error)
}

/*
WorkflowService 工作流服务
提供了对工作流的基本操作
*/
type WorkflowService interface {
	// GenerateWorkflowID 生成工作流ID
	// 为使用者提供一个唯一的工作流ID，在调用StartWorkflow时可以使用该ID
	// 返回值:
	//   - workflowID: 生成的工作流唯一标识符
	//   - err: 生成过程中的错误信息
	GenerateWorkflowID(ctx context.Context) (workflowID string, err error)

	// StartWorkflow 启动审批流
	// 审批流启动成功后，下一级的审批任务包含发起人，则任务会被自动审批掉
	// 如果启动的是草稿，则会把原来的草稿删除，然后启动新的审批流
	StartWorkflow(ctx context.Context, req StartWorkFlowRequest) (err error)

	// SaveWorkflowDraft 暂存工作流草稿
	// 只创建工作流实体并存储到数据库中，不会创建节点和任务
	SaveWorkflowDraft(ctx context.Context, req StartWorkFlowRequest) (err error)

	// RestartWorkflow 重启审批流
	RestartWorkflow(ctx context.Context, req RestartWorkFlowRequest) (err error)

	// UpdateWorkflowContent 更新工作流提交的内容
	UpdateWorkflowContent(ctx context.Context, workflowID, formContent string, businessParams BusinessParams) (err error)

	// RemoveWorkflow 移除工作流
	RemoveWorkflow(ctx context.Context, workflowID string) (err error)

	// CancelWorkflow 撤销工作流
	// 该方法会把工作流、工作流当前的节点和还未审批的任务的状态都设置为已撤销
	CancelWorkflow(ctx context.Context, workflowID string) (err error)

	// GetWorkflows 获取审批流
	// 查询的结果会把草稿放在最前面，然后再根据创建日期进行倒叙排列
	GetWorkflows(ctx context.Context, req GetWorkflowsRequest) (result []ActivatedWorkflow, total int64, err error)

	// GetWorkflow 根据ID获取审批流
	GetWorkflow(ctx context.Context, workflowID string) (result ActivatedWorkflow, err error)

	// GetNode 根据ID获取节点详情
	GetNode(ctx context.Context, nodeID string) (result ActivatedNode, err error)

	// GetWorkflowProgress 根据工作流ID查询整个工作流进度
	// 返回工作流的完整进度信息，包括所有节点的状态和审批情况
	GetWorkflowProgress(ctx context.Context, workflowID string) (result WorkflowProgress, err error)

	SubscribeEvents(ctx context.Context) <-chan Event
}

/*
TaskService 任务服务
提供了对审批任务的基本操作
*/
type TaskService interface {
	// Review 审批
	// 如果下级节点的任务包含当前审批人，则会自动审批掉
	Review(ctx context.Context, req ReviewRequest) (err error)

	// GetNodeReviewTasks 获取审批任务列表
	GetNodeReviewTasks(ctx context.Context, req GetNodeReviewTasksRequest) (result []NodeReviewTask, total int64, err error)

	// ChangeNodeReviewer 更改节点办理人员
	// 通过选择未完成审批的节点选择某个人员即可替换该人员
	ChangeNodeReviewer(ctx context.Context, req ChangeNodeReviewerRequest) (err error)

	// AddNodeReviewer 添加同环节办理人员
	// 通过选择某个未完成的环节，添加人员即可
	AddNodeReviewer(ctx context.Context, req AddNodeReviewerRequest) (err error)
}

// AutoApprovalStrategy 自动审批策略类型
type AutoApprovalStrategy string

// 自动审批策略枚举
const (
	// AutoApprovalStrategyAdjacent 相邻策略：相同审批人连续在相邻的节点中出现才触发自动审批
	AutoApprovalStrategyAdjacent AutoApprovalStrategy = "ADJACENT"
	// AutoApprovalStrategyAny 任意策略：审批人只要出现就执行自动审批
	AutoApprovalStrategyAny AutoApprovalStrategy = "ANY"
)

// WorkflowTemplateConfig 工作流模板配置
type WorkflowTemplateConfig struct {
	// Name 工作流模板名称
	Name string `json:"name"`

	// NodeTemplateConfigs 节点模板配置
	// 根据顺序决定谁是第一个节点，然后每个节点的下一个节点也是根据顺序来判断
	NodeTemplateConfigs []NodeTemplateConfig `json:"nodeTemplateConfigs"`

	// AutoApprovalConfig 自动审批配置
	AutoApprovalConfig AutoApprovalConfig `json:"autoApprovalConfig"`

	// TimeoutAlertHours 超时告警小时数
	// 当节点审批超过指定小时数时，系统将发送超时告警
	TimeoutAlertHours int `json:"timeoutAlertHours"`
}

// AutoApprovalConfig 自动审批配置
type AutoApprovalConfig struct {
	// Enable 是否启用自动审批功能
	Enable bool `json:"enable"`
	// Strategy 自动审批策略
	// 自动审批举例：如果发起人/本层节点审批人和下一个节点的审批人是同一个人，那么下一个节点的审批任务将自动审批通过
	Strategy AutoApprovalStrategy `json:"strategy"`
}

// ApprovalStrategy 审批策略类型
type ApprovalStrategy string

// 审批策略枚举
const (
	// ApprovalStrategyOr 或批策略：任意一人通过即可通过，任意一人拒绝即拒绝
	ApprovalStrategyOr ApprovalStrategy = "OR"
	// ApprovalStrategyAnd 与批策略：所有人通过才能通过，任意一人拒绝即拒绝
	ApprovalStrategyAnd ApprovalStrategy = "AND"
)

// NodeTemplateConfig 节点模板配置
type NodeTemplateConfig struct {
	// NodeTemplateID 节点模板ID，用于在条件节点中引用其他节点
	NodeTemplateID string `json:"nodeTemplateId,omitempty"`

	// NodeTemplateName 节点模板名称
	NodeTemplateName string `json:"nodeTemplateName"`

	// Kind 节点类型，1:审批类型节点，2:条件类型节点，3:开始节点，4：结束节点
	// 审批类型节点：该节点会自动发送审批任务，需要进行审批才能通过该节点（传统意义上的"审批节点"）
	// 条件类型节点：该节点作为条件判断节点，根据条件判断是否需要流转到下一个节点（可以理解为流程图中的菱形）
	NodeTemplateKind int `json:"nodeTemplateKind"`

	// NextNodeTemplateID 下一个节点模板ID
	// 当NodeTemplateKind为1(审批类型节点)或3(开始节点)时，此字段指定下一个节点
	// 当NodeTemplateKind为2(条件类型节点)或4(结束节点)时，此字段为空
	NextNodeTemplateID string `json:"nextNodeTemplateId,omitempty"`

	// WorkflowTemplateID 所属工作流模板的ID
	WorkflowTemplateID string `json:"workflowTemplateId"`

	// 节点审批配置
	ReviewerConfig NodeTemplateReviewerConfig `json:"nodeTemplateReviewerConfig"`

	// BusinessParams 业务参数
	BusinessParams BusinessParams `json:"businessParams"`

	// ConditionRules 条件规则列表
	// 用于条件节点的条件判断逻辑，支持复杂的条件组合和跳转规则
	// 条件评估流程：
	// 1. 按ConditionRules数组顺序逐一评估每个条件规则
	// 2. 对于每个ConditionRule，评估其内部的ConditionGroups
	// 3. 如果ConditionRule中的任意一个ConditionGroup满足，则该ConditionRule满足
	// 4. 如果ConditionRule满足，返回该ConditionRule.NextNodeTemplateID
	// 5. 如果所有ConditionRule都不满足，使用默认的NextNodeTemplateID
	//
	// 使用示例：
	// 请假审批流程中，根据请假天数和部门进行不同的审批路径：
	// - 请假天数<=3 AND 部门=技术部 -> 直属领导审批
	// - 请假天数>3 AND 请假天数<=7 -> 部门经理审批
	// - 请假天数>7 -> 总监审批
	ConditionRules []ConditionRule `json:"conditionRules"`
}

// LogicalOperator 逻辑操作符类型
type LogicalOperator string

const (
	// LogicalOperatorAnd AND逻辑操作符 - 所有条件都必须满足
	LogicalOperatorAnd LogicalOperator = "AND"
	// LogicalOperatorOr OR逻辑操作符 - 任意一个条件满足即可
	LogicalOperatorOr LogicalOperator = "OR"
)

// Expression 条件表达式结构体
// 用于定义条件节点中的单个条件判断逻辑
// 每个Expression代表一个基础的"参数 操作符 值"的比较表达式
type Expression struct {
	// Param 参数名称，支持点号路径访问
	// 对应ConditionParams中的键名，支持嵌套访问如"user.name"、"config.settings.timeout"
	// 例如："amount"(金额)、"user.department"(用户部门)、"request.priority"(请求优先级)等
	Param string `json:"param"`

	// Operator 比较操作符
	// 定义参数值与期望值的比较方式：
	// "==" - 等于，参数值等于指定值时条件成立
	// "!=" - 不等于，参数值不等于指定值时条件成立
	// ">" - 大于，参数值大于指定值时条件成立
	// "<" - 小于，参数值小于指定值时条件成立
	// ">=" - 大于等于，参数值大于等于指定值时条件成立
	// "<=" - 小于等于，参数值小于等于指定值时条件成立
	// "⊇" - 包含，参数值包含指定值时条件成立
	// "!⊇" - 不包含，参数值不包含指定值时条件成立
	Operator string `json:"operator"`

	// Value 期望值
	// 与参数值进行比较的目标值，支持任意类型(string、int、bool等)
	// 类型必须与ConditionParams中对应参数的类型兼容
	// 例如：字符串"manager"、数字100、布尔值true等
	Value any `json:"value"`

	// Kind 参数类型，用于指定如何解析和比较参数值
	// 支持的类型："string", "int", "float", "bool", "array", "object"
	// 当指定类型时，系统会根据类型进行值转换和比较
	Kind string `json:"kind"`
}

// ConditionGroup 条件组
// 用于定义一组条件的组合逻辑
// 支持多个条件通过AND/OR逻辑操作符进行组合
type ConditionGroup struct {
	// Conditions 条件列表
	// 包含多个基础条件表达式，通过逻辑操作符进行组合
	Conditions []Expression `json:"conditions"`

	// LogicalOperator 逻辑操作符
	// 定义条件之间的逻辑关系：
	// - "AND": 所有条件都必须满足
	// - "OR": 任意一个条件满足即可
	// 默认为"AND"
	LogicalOperator LogicalOperator `json:"logicalOperator"`
}

// ConditionRule 条件规则
// 包含一组条件组和对应的跳转节点ID
type ConditionRule struct {
	// ConditionGroups 条件组列表
	ConditionGroups []ConditionGroup `json:"conditionGroups"`
	// NextNodeTemplateID 条件规则满足时跳转的目标节点ID
	// 当条件规则的逻辑表达式评估为true时，工作流将跳转到此节点
	// 必须是有效的节点模板ID，否则会导致工作流执行异常
	NextNodeTemplateID string `json:"nextNodeTemplateId"`
}

// NodeTemplateReviewerConfig 节点模板审批人配置
type NodeTemplateReviewerConfig struct {
	// Kind 类型 1：指定好了用户id，其它数字类型都表明是角色类型的审批人
	// sally会在需要时调用hook获取（Kind会作为hook的参数）
	Kind int `json:"kind"`
	// Reviewers 审批人列表
	// 当Kind=1时，该字段表示业务审批人ID列表
	// 当Kind为其它值时，该字段表示业务审批者编号列表，会在hook中用于查询ReviewerID
	Reviewers []string `json:"reviewers"`
	// ApprovalStrategy 审批策略，空值或OR表示或批，AND表示与批
	ApprovalStrategy ApprovalStrategy `json:"approvalStrategy"`
}

func (n NodeTemplateReviewerConfig) GetReviewerIDs() (result []string) {
	if n.Kind == 1 {
		return n.Reviewers
	}
	return result
}

func (n NodeTemplateReviewerConfig) GetReviewerNos() (result []string) {
	if n.Kind != 1 {
		return n.Reviewers
	}
	return result
}

type BusinessParams map[string]any

func NewBusinessParams(params string) (result BusinessParams, err error) {
	err = sonic.Unmarshal([]byte(params), &result)
	return result, err
}
func (b BusinessParams) Marshal() (string, error) {
	result, err := sonic.Marshal(b)
	return string(result), err
}

func (b BusinessParams) SetText(value string) {
	b["text"] = value
}
func (b BusinessParams) GetText() string {
	if v, ok := b["text"]; ok {
		return v.(string)
	}

	return ""
}

type StartWorkFlowRequest struct {
	WorkflowID         string `json:"workflowId"`
	BusinessID         string `json:"businessId"`
	BusinessCode       string `json:"businessCode"`
	WorkflowTemplateID string `json:"workflowTemplateId"`
	FormContent        string `json:"formContent"`
	SponsorID          string `json:"sponsorId"`
	Conclusion         string `json:"conclusion"`
	BusinessParams     BusinessParams
}

type RestartWorkFlowRequest struct {
	BusinessID     string `json:"businessId"`
	BusinessCode   string `json:"businessCode"`
	WorkflowID     string `json:"workflowId"`
	FormContent    string `json:"formContent"`
	SponsorID      string `json:"sponsorId"`
	BusinessParams BusinessParams
}

type ReviewerConfig struct {
	NodeTemplateID         string
	BusinessReviewDepartID string
	BusinessReviewerNo     string
}

type DBConfig struct {
	Host            string
	Port            string
	User            string
	Password        string
	Schema          string
	MaxIdleConns    int
	ConnMaxLifetime int64
	MaxOpenConns    int
}

// Hook 钩子函数 服务中会调用到的外界能力
type Hook interface {
	// GetReviewerIDs 获取审批人id
	GetReviewerIDs(ctx context.Context, roleKind int, reviewerNos []string, formContent string, params BusinessParams) (userIDs []string, err error)
}

func NewClerkService(reference Reference, hook Hook, enableTimeoutAlert bool) ClerkService {
	clerk := &Clerk{
		Reference:    reference,
		Hook:         hook,
		EventService: NewDefaultEventService(),
	}

	// 根据参数决定是否启动超时提醒定时任务
	if enableTimeoutAlert {
		timeoutAlertScheduler := NewTimeoutAlertScheduler(reference, clerk.EventService)
		timeoutAlertScheduler.Start()
	}

	return clerk
}

type ReviewRequest struct {
	NodeReviewerTaskID string
	// Comment 审批意见，使用BusinessParams类型支持多种数据类型
	// 注意：Comment中的"text"字段用于存储文本信息，保持与其他系统的兼容性
	Comment BusinessParams
	Status  int

	tx *gorm.DB
}

func (r ReviewRequest) IsPass() bool {
	return r.Status == ReviewPassed
}

func (r ReviewRequest) IsRejected() bool {
	return r.Status == ReviewRejected
}

type GetWorkflowsRequest struct {
	PageCond
	CommonSearchCond
	// SponsorID 流程发起人的ID
	SponsorID string

	BusinessCode string
	BusinessID   string

	WorkflowName   string
	WorkflowStatus int
	// CurrentNodeReviewerIDs 当前节点审批人ID列表
	CurrentNodeReviewerIDs []string
	// ReviewedByUserIDs 已审批过的用户ID列表
	ReviewedByUserIDs []string

	BusinessParams BusinessParams
}
type PageCond struct {
	NoPage   bool `json:"noPage"`
	PageNo   int  `json:"pageNo"`
	PageSize int  `json:"pageSize"`
}

type CommonSearchCond struct {
	IDs               []string `json:"ids"`
	FormContentSearch string   `json:"formContentSearch"`
	// CreatedAtStart 创建时间开始范围
	CreatedAtStart time.Time `json:"createdAtStart"`
	// CreatedAtEnd 创建时间结束范围
	CreatedAtEnd time.Time `json:"createdAtEnd"`

	// UpdatedAtStart 更新时间开始范围
	UpdatedAtStart time.Time `json:"updatedAtStart"`
	// UpdatedAtEnd 更新时间结束范围
	UpdatedAtEnd time.Time `json:"updatedAtEnd"`
}

type GetNodeReviewTasksRequest struct {
	PageCond
	CommonSearchCond
	ReviewerID string

	BusinessCode string
	BusinessID   string
	WorkflowID   string

	// Statuses 审批任务状态
	// 可选值：
	// 1：审核中
	// 2：审核通过
	// -1：审核未通过
	// -5：已撤销
	// -10：已归档
	// 数组中的值会被OR链接，作为查询条件
	// 例如：Statuses = []int{1, 2}，则查询条件为：status = 1 OR status = 2
	Statuses []int

	WorkflowName           string
	WorkflowCreateUser     string
	WorkflowCreatedAtStart time.Time
	WorkflowCreatedAtEnd   time.Time
	WorkflowBusinessParams BusinessParams
	WorkflowStatus         int
	WorkflowSponsorID      string

	NodeID  string
	NodeIDs []string // 支持批量查询多个节点ID
}

type ActivatedWorkflow struct {
	ID                     string
	FormContent            string
	Name                   string
	BusinessID             string
	BusinessCode           string
	CurrentNodeID          string
	CurrentNodeName        string
	CurrentNodeTemplateID  string
	CurrentNodeReviewerIDs []string
	Status                 int
	BusinessParams         BusinessParams
	Conclusion             string
	SponsorID              string
	CreatedAt              time.Time
	UpdatedAt              time.Time

	CurrentNodeReviewTasks []NodeReviewTask
}

// ActivatedNode 激活的节点详情
type ActivatedNode struct {
	ID             string
	WorkflowID     string
	NodeTemplateID string
	Status         int
	CreatedAt      time.Time
	UpdatedAt      time.Time

	// 节点模板信息
	NodeTemplateName           string
	NodeTemplateKind           int
	ApprovalStrategy           string
	NextNodeTemplateID         string
	NodeTemplateBusinessParams BusinessParams

	// 审批任务列表
	NodeReviewTasks []NodeReviewTask
}

type NodeReviewTask struct {
	ID string
	// Comment 审批意见，使用BusinessParams类型支持多种数据类型
	// 注意：Comment中的"text"字段用于存储文本信息，保持与其他系统的兼容性
	Comment            BusinessParams
	WorkflowID         string
	WorkflowName       string
	WorkflowCreatedAt  time.Time
	NodeID             string
	NodeName           string
	NodeBusinessParams BusinessParams
	NodeCreatedAt      time.Time
	Status             int
	FormContent        string
	ReviewerID         string
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

// ChangeNodeReviewerRequest 更改节点办理人员请求
type ChangeNodeReviewerRequest struct {
	TaskID        string `json:"taskId"`        // 要更改的审批任务ID
	NewReviewerID string `json:"newReviewerId"` // 新的审批人员ID
}

// AddNodeReviewerRequest 添加同环节办理人员请求
type AddNodeReviewerRequest struct {
	NodeID     string `json:"nodeId"`     // 节点ID
	ReviewerID string `json:"reviewerId"` // 要添加的审批人员ID
}

// WorkflowProgress 工作流进度信息
type WorkflowProgress struct {
	WorkflowID     string         `json:"workflowId"`     // 工作流ID
	WorkflowName   string         `json:"workflowName"`   // 工作流名称
	Status         int            `json:"status"`         // 工作流状态
	SponsorID      string         `json:"sponsorId"`      // 发起人ID
	FormContent    string         `json:"formContent"`    // 表单内容
	BusinessParams BusinessParams `json:"businessParams"` // 业务参数
	NodeProgresses []NodeProgress `json:"nodeProgresses"` // 节点进度列表
}

// NodeProgress 节点进度信息
type NodeProgress struct {
	NodeTemplateID    string             `json:"nodeTemplateId"`    // 节点模板ID
	NodeTemplateName  string             `json:"nodeTemplateName"`  // 节点模板名称
	NodeID            string             `json:"nodeId"`            // 节点ID（如果节点已创建）
	Status            int                `json:"status"`            // 节点状态（如果节点已创建）
	ApprovalStrategy  string             `json:"approvalStrategy"`  // 审批策略
	CreatedAt         time.Time          `json:"createdAt"`         // 节点创建时间
	UpdatedAt         time.Time          `json:"updatedAt"`         // 节点更新时间
	ReviewTasks       []NodeProgressTask `json:"reviewTasks"`       // 审批任务列表（如果节点已创建）
	TemplateReviewers []TemplateReviewer `json:"templateReviewers"` // 节点模板审批人列表（如果节点未创建）
}

// NodeProgressTask 节点进度中的审批任务信息
type NodeProgressTask struct {
	TaskID     string `json:"taskId"`     // 任务ID
	ReviewerID string `json:"reviewerId"` // 审批人ID
	Status     int    `json:"status"`     // 任务状态
	// Comment 审批意见，使用BusinessParams类型支持多种数据类型
	// 注意：Comment中的"text"字段用于存储文本信息，保持与其他系统的兼容性
	Comment   BusinessParams `json:"comment"`   // 审批意见
	CreatedAt time.Time      `json:"createdAt"` // 任务创建时间
	UpdatedAt time.Time      `json:"updatedAt"` // 任务更新时间
}

// TemplateReviewer 模板审批人信息
type TemplateReviewer struct {
	ID             string `json:"id"`             // 审批人ID
	Kind           int    `json:"kind"`           // 审批人类型
	NodeTemplateID string `json:"nodeTemplateId"` // 节点模板ID
	ReviewerNos    string `json:"reviewerNos"`    // 业务审批人编号
	ReviewerIDs    string `json:"reviewerIds"`    // 审批人ID列表
}

// ToProgressTask 将NodeReviewTask转换为NodeProgressTask
// 用于简化数据结构转换过程，提高代码可读性
func (task NodeReviewTask) ToProgressTask() NodeProgressTask {
	return NodeProgressTask{
		TaskID:     task.ID,
		ReviewerID: task.ReviewerID,
		Status:     task.Status,
		Comment:    task.Comment,
		CreatedAt:  task.CreatedAt,
		UpdatedAt:  task.UpdatedAt,
	}
}

// ToTemplateReviewer 将NodeTemplateReviewer转换为TemplateReviewer
// 用于简化数据结构转换过程，提高代码可读性
func ToTemplateReviewer(reviewer entity.NodeTemplateReviewer) TemplateReviewer {
	return TemplateReviewer{
		ID:             reviewer.ID,
		Kind:           reviewer.Kind,
		NodeTemplateID: reviewer.NodeTemplateID,
		ReviewerNos:    reviewer.ReviewerNos,
		ReviewerIDs:    reviewer.ReviewerIDs,
	}
}
